package org.summerframework.core.util;

import org.summerframework.core.base.result.DefaultResultCode;
import org.summerframework.core.exception.SystemException;
import org.apache.commons.lang3.ArrayUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Created by shichao on 2017/3/16.
 */
public class ClassGenricTypeBeanUtils {

    public static Class getInterfacesGenricType(final Class clazz, Class interfaces, final int index) {
        Type genType = null;

        //返回表示此 Class 所表示的实体（类、接口、基本类型或 void）的直接超类的 Type。
        Type[] types = clazz.getGenericInterfaces();

        types = ArrayUtils.add(types, clazz.getGenericSuperclass());

        if (types.length > 0) {
            for (Type type : types) {
                if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType() instanceof Class && interfaces.isAssignableFrom((Class) ((ParameterizedType) type).getRawType())) {
                    return getGenricType((ParameterizedType) type, index);
                } else if (type instanceof Class && interfaces.isAssignableFrom((Class) type)) {
                    return getInterfacesGenricType((Class) type, interfaces, index);
                }
            }
        }

        return Object.class;
    }

    private static Class getGenricType(ParameterizedType genType, int index) {
        //返回表示此类型实际类型参数的 Type 对象的数组。
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {
            return Object.class;
        }
        if (params[index] instanceof Class) {
            return (Class) params[index];
        }

        return Object.class;
    }

    public static Class getSuperClassGenricType(final Class clazz, final int index) {
        //返回表示此 Class 所表示的实体（类、接口、基本类型或 void）的直接超类的 Type。
        Type genType = clazz.getGenericSuperclass();

        if (!(genType instanceof ParameterizedType)) {
            return Object.class;
        }
        //返回表示此类型实际类型参数的 Type 对象的数组。
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
            return Object.class;
        }

        return (Class) params[index];
    }

    public static Object newInstance(Class clazz, int index) {
        try {
            return ClassGenricTypeBeanUtils.getSuperClassGenricType(clazz, index).newInstance();
        } catch (Exception ignored) {
            throw new SystemException(DefaultResultCode.SYSTEM_ERROR, ignored);
        }
    }

    public static Object newInstance(Class clazz, Class interfaces, int index) {
        try {
            return ClassGenricTypeBeanUtils.getInterfacesGenricType(clazz, interfaces, index).newInstance();
        } catch (Exception ignored) {
            throw new SystemException(DefaultResultCode.SYSTEM_ERROR, ignored);
        }
    }

}
